package net.xxcxcxcx.xc_enhancedmob.render.particle.custom;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleFactory;
import net.minecraft.client.particle.SpriteProvider;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.particle.DefaultParticleType;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Quaternion;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3f;

import java.util.Random;

//这是一个会永远指向target方向的粒子，如果使用的话想要所有方向都看见需要渲染两个面
@Environment(value = EnvType.CLIENT)
public class CustomDirectionBaseParticle extends CustomBaseParticle {
    public static Random random = new Random();
    private Vec3d target = null;
    private boolean DirectionalLock = false;
    private float angleself;
    private float prevangleself;
    private float speedangleself;

    public CustomDirectionBaseParticle(SpriteProvider spriteProvider, ClientWorld world, double x, double y, double z) {
        this(spriteProvider, world, x, y, z, 0, 0, 0);
    }

    public CustomDirectionBaseParticle(SpriteProvider spriteProvider, ClientWorld world, double x, double y, double z,
                                       double velocityX, double velocityY, double velocityZ) {
        this(spriteProvider, world, x, y, z, velocityX, velocityY, velocityZ, 0, 1, 100, 1, 1, 1, 1);
    }

    public CustomDirectionBaseParticle(SpriteProvider spriteProvider, ClientWorld world, double x, double y, double z,
                                       double velocityX, double velocityY, double velocityZ, float anglespeed,
                                       float scale, int maxage, float red, float green, float blue, float alpha) {
        this(spriteProvider, world, x, y, z, velocityX, velocityY, velocityZ, anglespeed, scale, maxage, red, green, blue, alpha, new Vec3d(x, y + 1, z), 0.1f, false);
    }

    public CustomDirectionBaseParticle(SpriteProvider spriteProvider, ClientWorld world, double x, double y, double z,
                                       double velocityX, double velocityY, double velocityZ, float anglespeed,
                                       float scale, int maxage, float red, float green, float blue, float alpha,
                                       Vec3d target, float speedangleself, boolean DirectionalLock) {
        super(spriteProvider, world, x, y, z, velocityX, velocityY, velocityZ, anglespeed, scale, maxage, red, green, blue, alpha);
        this.setTarget(target);
        this.setSpeedangleself(speedangleself);
        this.setDirectionalLock(DirectionalLock);
    }

    public Vec3d getTarget() {
        return target;
    }

    public void setTarget(Vec3d target) {
        this.target = target;
    }

    //渲染粒子
    @Override
    public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) {
        if (getTarget() != null) {
            Vec3d nowtarget;
            if (isDirectionalLock()) {
                nowtarget = getTarget().add(x, y, z);
            } else {
                nowtarget = getTarget();
            }
            Quaternion quaternion;
            Vec3d vec3d = camera.getPos();
            float f = (float) (MathHelper.lerp(tickDelta, this.prevPosX, this.x) - vec3d.getX());
            float g = (float) (MathHelper.lerp(tickDelta, this.prevPosY, this.y) - vec3d.getY());
            float h = (float) (MathHelper.lerp(tickDelta, this.prevPosZ, this.z) - vec3d.getZ());
            Vec3d vec3d1 = (new Vec3d(x, y, z)).relativize(new Vec3d(nowtarget.getX(), nowtarget.getY(), nowtarget.getZ())).normalize();
            Vec3d vec3d2 = new Vec3d(0, 1, 0);
            Vec3d vec3d3 = vec3d1.crossProduct(vec3d2).normalize();
            float angle = (float) Math.acos((vec3d1.x * vec3d2.x + vec3d1.y * vec3d2.y + vec3d1.z * vec3d2.z) / (vec3d1.length() * vec3d2.length()));
            if (Math.abs(vec3d1.y) > 0.999f) {
                quaternion = new Quaternion(new Vec3f(0, 0, 1), -angle, false);
            } else {
                quaternion = new Quaternion(new Vec3f(vec3d3), -angle, false);
            }
            if (this.getAngleself() != 0.0f) {
                float i = MathHelper.lerp(tickDelta, this.getPrevangleself(), this.getAngleself());
                quaternion.hamiltonProduct(Vec3f.POSITIVE_Y.getRadialQuaternion(i));
            }
            if (this.angle != 0.0f) {
                float i = MathHelper.lerp(tickDelta, this.prevAngle, this.angle);
                quaternion.hamiltonProduct(new Quaternion(new Vec3f(f, g, h), i, false));
            }
            Vec3f[] vec3fs = new Vec3f[]{new Vec3f(-1.0f, 0.0f, -1.0f), new Vec3f(-1.0f, 0.0f, 1.0f), new Vec3f(1.0f, 0.0f, 1.0f), new Vec3f(1.0f, 0.0f, -1.0f)};
            float j = this.getSize(tickDelta);
            for (int k = 0; k < 4; ++k) {
                Vec3f vec3f2 = vec3fs[k];
                vec3f2.rotate(quaternion);
                vec3f2.scale(j);
                vec3f2.add(f, g, h);
            }
            float l = this.getMinU();
            float m = this.getMaxU();
            float n = this.getMinV();
            float o = this.getMaxV();
            int p = this.getBrightness(tickDelta);
            float alpha = getColorAlpha(tickDelta);
            vertexConsumer.vertex(vec3fs[0].getX(), vec3fs[0].getY(), vec3fs[0].getZ()).texture(m, o).color(this.colorRed, this.colorGreen, this.colorBlue, alpha).light(p).next();
            vertexConsumer.vertex(vec3fs[1].getX(), vec3fs[1].getY(), vec3fs[1].getZ()).texture(m, n).color(this.colorRed, this.colorGreen, this.colorBlue, alpha).light(p).next();
            vertexConsumer.vertex(vec3fs[2].getX(), vec3fs[2].getY(), vec3fs[2].getZ()).texture(l, n).color(this.colorRed, this.colorGreen, this.colorBlue, alpha).light(p).next();
            vertexConsumer.vertex(vec3fs[3].getX(), vec3fs[3].getY(), vec3fs[3].getZ()).texture(l, o).color(this.colorRed, this.colorGreen, this.colorBlue, alpha).light(p).next();
        } else {
            super.buildGeometry(vertexConsumer, camera, tickDelta);
        }
    }

    @Override
    public float getSize(float tickDelta) {
        return this.getScale();
    }

    //垂直于动画粒子所在面的轴旋转
    public void tickangleself() {
        this.setPrevangleself(this.getAngleself());
        this.setAngleself(this.getAngleself() + this.getSpeedangleself());
    }

    //每tick干的事情
    @Override
    public void tick() {
        super.tick();
        tickangleself();
    }

    public boolean isDirectionalLock() {
        return DirectionalLock;
    }

    public void setDirectionalLock(boolean directionalLock) {
        DirectionalLock = directionalLock;
    }

    public float getAngleself() {
        return angleself;
    }

    public void setAngleself(float angleself) {
        this.angleself = angleself;
    }

    public float getPrevangleself() {
        return prevangleself;
    }

    public void setPrevangleself(float prevangleself) {
        this.prevangleself = prevangleself;
    }

    public float getSpeedangleself() {
        return speedangleself;
    }

    public void setSpeedangleself(float speedangleself) {
        this.speedangleself = speedangleself;
    }

    @Environment(value = EnvType.CLIENT)
    public static class Factory implements ParticleFactory<DefaultParticleType> {
        private final SpriteProvider spriteProvider;

        public Factory(SpriteProvider spriteProvider) {
            this.spriteProvider = spriteProvider;
        }

        @Override
        public Particle createParticle(DefaultParticleType defaultParticleType, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i) {
            return new CustomDirectionBaseParticle(spriteProvider, clientWorld, d, e, f, g, h, i);
        }
    }
}
